#pragma once
#include <google/protobuf/service.h>
#include <regex>
#include "fastrpc/base.hpp"
#include "fastrpc/log.hpp"
#include "fastrpc/net.hpp"
#include "fastrpc/rpc/common/rpc_util.hpp"
#include "fastrpc/rpc/fastrpc/fastrpc_controller.hpp"
#include "fastrpc/rpc/rpc_framed.hpp"
namespace fastrpc::rpc {

using namespace fastrpc::log;
using namespace fastrpc::io;
using namespace fastrpc::net;
using namespace fastrpc::async;
using namespace fastrpc;
class RpcClient;
class RpcClient {
private:
    explicit RpcClient(TcpStream&& stream) : stream_{std::move(stream)} {}

public:
    static auto GetInstance(std::string_view host, uint16_t port)
        -> Task<rpc::RpcResult<RpcClient>> {
        auto addr = SocketAddr::parse(host, port).value();
        auto stream = co_await TcpStream::connect(addr);
        if (!stream) {
            console.error("{}", stream.error().message());
            co_return std::unexpected{rpc::make_rpc_error(rpc::RpcError::ConnectFailed)};
        }
        co_return RpcClient{std::move(stream.value())};
    }

    template <class T, class F>
    auto call(const std::string& id, const std::string& method_name, T request) -> Task<F> {
        std::shared_ptr<rpc::RpcFramed<>> rpc_framed = std::make_shared<rpc::RpcFramed<>>(stream_);
        std::array<char, 1024>            buf{};
        // 创建一个 FastPBProtocol 消息
        // 创建并初始化一个 FastPBProtocol 对象
        fastrpc::rpc::FastPBProtocol protocol;
        protocol.m_msg_id = id;  // 消息 ID
        // protocol.m_pb_data = "";  // Protobuf 数据
        protocol.m_method_name = method_name;
        protocol.m_err_code = 0;
        protocol.m_err_info = "err_info";
        if (!request.SerializeToString(&protocol.m_pb_data)) {
            console.error("request protobuf SerializeToString failed!!!");
            co_return F{};
        }

        // 编码并发送消息
        auto write_result = co_await rpc_framed->write_frame(protocol);
        if (!write_result) {
            console.error("Error sending message: {}", write_result.error().message());
            co_return F{};
        }

        // 接收并解码服务器的响应
        auto read_result = co_await rpc_framed->read_frame(buf);
        if (!read_result) {
            console.error("Error receiving response: {}", read_result.error().message());
            co_return F{};
        }

        // 输出接收到的响应
        protocol_ = read_result.value();
        F response;
        response.ParseFromString(protocol_.m_pb_data);
        co_return response;
    }

    FastPBProtocol& get_protocol() {
        return protocol_;
    }

private:
    TcpStream      stream_;
    FastPBProtocol protocol_;
};

}  // namespace fastrpc::rpc
